#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
基于豆包大模型的智能POI解析器
使用Doubao-Seed-1.6模型，支持调用次数限制
"""

import json
import logging
import time
from typing import Dict, Optional
import requests
from datetime import datetime, timedelta

class DoubanAIParser:
    """使用豆包大模型的智能POI解析器"""
    
    def __init__(self, api_key: str = None):
        """初始化豆包API解析器"""
        self.api_key = api_key or "your_douban_api_key_here"
        self.api_url = "https://api.volcengine.com/v1/services/aigc/text-generation/generation"
        
        # 设置日志
        self.logger = logging.getLogger(__name__)
        
        # 设置请求头
        self.headers = {
            "Authorization": f"Bearer {self.api_key}",
            "Content-Type": "application/json"
        }
        
        # 调用次数限制
        self.max_calls_per_day = 100  # 每日最大调用次数
        self.max_calls_per_minute = 10  # 每分钟最大调用次数
        self.call_history = []  # 调用历史记录
        
    def can_make_call(self) -> bool:
        """检查是否可以发起API调用"""
        now = datetime.now()
        
        # 清理过期的调用记录
        self.call_history = [call_time for call_time in self.call_history 
                           if now - call_time < timedelta(days=1)]
        
        # 检查每日限制
        if len(self.call_history) >= self.max_calls_per_day:
            self.logger.warning("已达到每日API调用限制")
            return False
        
        # 检查每分钟限制
        recent_calls = [call_time for call_time in self.call_history 
                       if now - call_time < timedelta(minutes=1)]
        if len(recent_calls) >= self.max_calls_per_minute:
            self.logger.warning("已达到每分钟API调用限制")
            return False
        
        return True
    
    def record_call(self):
        """记录API调用"""
        self.call_history.append(datetime.now())
    
    def parse_note(self, text: str, url: str = "") -> Optional[Dict]:
        """
        使用豆包大模型解析小红书笔记
        
        Args:
            text: 提取的文本内容
            url: 原始链接
            
        Returns:
            解析后的笔记数据
        """
        # 检查调用限制
        if not self.can_make_call():
            self.logger.warning("API调用受限，跳过AI解析")
            return None
        
        try:
            self.logger.info("开始使用豆包大模型解析笔记")
            
            # 构建提示词
            prompt = self._build_prompt(text)
            
            # 构建请求数据
            request_data = {
                "model": "doubao-seed-1.6",  # 使用Doubao-Seed-1.6模型
                "input": {
                    "messages": [
                        {
                            "role": "user",
                            "content": prompt
                        }
                    ]
                },
                "parameters": {
                    "temperature": 0.1,  # 低温度，更确定性的输出
                    "max_tokens": 1500,  # 限制输出长度，提高速度
                    "top_p": 0.9
                }
            }
            
            # 记录调用
            self.record_call()
            
            # 调用豆包API
            response = requests.post(
                self.api_url,
                headers=self.headers,
                json=request_data,
                timeout=15  # 设置较短的超时时间，提高响应速度
            )
            
            if response.status_code == 200:
                result = response.json()
                if 'output' in result and 'text' in result['output']:
                    ai_response = result['output']['text']
                    # 解析AI返回的JSON
                    parsed_data = self._parse_ai_response(ai_response)
                    if parsed_data:
                        self.logger.info(f"豆包AI解析成功，提取到 {len(parsed_data.get('places', []))} 个POI")
                        return parsed_data
                    else:
                        self.logger.warning("豆包AI返回的数据格式无效")
                        return None
                else:
                    self.logger.error("豆包API返回格式异常")
                    return None
            else:
                self.logger.error(f"豆包API调用失败，状态码: {response.status_code}")
                return None
                
        except Exception as e:
            self.logger.error(f"豆包AI解析失败: {str(e)}")
            return None
    
    def _build_prompt(self, text: str) -> str:
        """构建发送给豆包的提示词"""
        prompt = f"""
你是一个专业的旅游路线分析助手。请分析以下小红书笔记，提取其中的地点信息（POI）。

**任务要求：**
1. 识别笔记中提到的所有具体地点（如车站、景点、餐厅、商店等）
2. 过滤掉描述性文字、人物、情感表达等非地点内容
3. 返回结构化的JSON数据

**输入文本：**
{text}

**输出格式要求：**
请返回一个JSON对象，包含以下字段：
{{
    "title": "笔记标题",
    "content": "笔记主要内容摘要",
    "places": [
        {{
            "name": "地点名称",
            "description": "地点描述",
            "category": "地点类别",
            "address": "地址信息（如果有）"
        }}
    ],
    "tags": ["标签1", "标签2"],
    "route_type": "路线类型（如：步行、观光等）"
}}

**注意事项：**
- 只提取真实存在的地点，不要包含虚拟或描述性内容
- 地点名称要准确，不要包含多余的修饰词
- 如果文本中没有明确的地点信息，返回空的地点列表
- 确保返回的是有效的JSON格式

请直接返回JSON，不要包含其他文字说明。
"""
        return prompt
    
    def _parse_ai_response(self, response_text: str) -> Optional[Dict]:
        """解析AI返回的响应"""
        try:
            # 清理响应文本，提取JSON部分
            json_start = response_text.find('{')
            json_end = response_text.rfind('}') + 1
            
            if json_start == -1 or json_end == 0:
                self.logger.error("AI响应中未找到JSON内容")
                return None
            
            json_text = response_text[json_start:json_end]
            
            # 解析JSON
            parsed_data = json.loads(json_text)
            
            # 验证数据结构
            if not isinstance(parsed_data, dict):
                return None
            
            # 确保必要字段存在
            if 'places' not in parsed_data:
                parsed_data['places'] = []
            
            if 'title' not in parsed_data:
                parsed_data['title'] = "未命名路线"
            
            if 'content' not in parsed_data:
                parsed_data['content'] = ""
            
            if 'tags' not in parsed_data:
                parsed_data['tags'] = []
            
            # 转换地点数据格式，与现有系统兼容
            places = []
            for place in parsed_data['places']:
                if isinstance(place, dict) and 'name' in place:
                    places.append({
                        'name': place['name'],
                        'description': place.get('description', ''),
                        'address': place.get('address', place['name']),
                        'category': self._map_category(place.get('category', '')),
                        'coordinates': self._get_coordinates_from_address(place.get('address', place['name'])),
                        'source': 'douban_ai'
                    })
            
            parsed_data['places'] = places
            
            return parsed_data
            
        except json.JSONDecodeError as e:
            self.logger.error(f"JSON解析失败: {str(e)}")
            self.logger.error(f"原始响应: {response_text}")
            return None
        except Exception as e:
            self.logger.error(f"解析AI响应失败: {str(e)}")
            return None
    
    def _map_category(self, ai_category: str) -> str:
        """将AI返回的类别映射到系统类别"""
        category_mapping = {
            'transportation': 'transportation',
            'station': 'transportation',
            '地铁站': 'transportation',
            '车站': 'transportation',
            
            'attraction': 'attraction',
            '景点': 'attraction',
            '博物馆': 'attraction',
            '展览馆': 'attraction',
            '雕塑馆': 'attraction',
            
            'shopping': 'shopping',
            '购物': 'shopping',
            '商业街': 'shopping',
            '商店': 'shopping',
            
            'restaurant': 'restaurant',
            '餐厅': 'restaurant',
            '美食': 'restaurant',
            '汉堡店': 'restaurant',
            
            'temple': 'attraction',
            '神社': 'attraction',
            '寺庙': 'attraction',
            
            'park': 'park',
            '公园': 'park',
            '广场': 'park'
        }
        
        return category_mapping.get(ai_category.lower(), 'other')
    
    def _get_coordinates_from_address(self, address: str) -> Dict[str, float]:
        """从地址获取坐标（实际项目中应该调用地理编码API）"""
        # 这里返回模拟坐标，实际项目中应该调用Google Geocoding API
        return {
            'latitude': 35.7278,
            'longitude': 139.7708
        }
    
    def is_available(self) -> bool:
        """检查豆包API是否可用"""
        return self.api_key != "your_douban_api_key_here"
    
    def get_usage_stats(self) -> Dict:
        """获取API使用统计"""
        now = datetime.now()
        today_calls = len([call_time for call_time in self.call_history 
                          if now - call_time < timedelta(days=1)])
        minute_calls = len([call_time for call_time in self.call_history 
                           if now - call_time < timedelta(minutes=1)])
        
        return {
            'today_calls': today_calls,
            'max_daily_calls': self.max_calls_per_day,
            'minute_calls': minute_calls,
            'max_minute_calls': self.max_calls_per_minute,
            'remaining_daily': self.max_calls_per_day - today_calls
        }
